import axios, { AxiosInstance, InternalAxiosRequestConfig, AxiosResponse } from 'axios'
import { ElMessage } from 'element-plus'
import router from '@/router'
import { ResponseCode, ResponseCodeMsg } from '../../doc/responseCode'

// 响应数据接口
export interface ApiResponse<T = any> {
  code: number
  message: string
  data: T
}

// 获取 API 基础 URL
// 开发环境（npm run dev）：使用代理路径（通过 vite 代理转发）
// 打包环境（build:dev/build:prd）：如果设置了固定域名则使用，否则使用相对路径（走地址栏域名）
const getBaseURL = (): string => {
  // 开发模式（npm run dev）：使用代理路径
  // import.meta.env.DEV 在开发服务器运行时为 true，打包后为 false
  if (import.meta.env.DEV) {
    // 开发环境使用代理路径，通过 vite 代理转发到后端
    return import.meta.env.VITE_API_BASE_URL || '/devApi'
  }
  
  // 打包后的环境（build:dev 或 build:prd）
  const apiTarget = import.meta.env.VITE_API_URL
  
  // 如果设置了固定域名，使用完整 URL（走固定域名）
  if (apiTarget && apiTarget.trim()) {
    // 确保 URL 以 / 结尾（如果路径不为空）
    const target = apiTarget.trim()
    return target.endsWith('/') ? target.slice(0, -1) : target
  }
  
  // 如果没有设置固定域名，使用相对路径（走地址栏域名）
  // 这样可以根据部署的域名自动适配
  return import.meta.env.VITE_API_BASE_URL || '/api'
}

// 创建 axios 实例
const service: AxiosInstance = axios.create({
  baseURL: getBaseURL(),
  timeout: 10000,
  headers: {
    'Content-Type': 'application/json;charset=UTF-8'
  }
})

// 请求拦截器
service.interceptors.request.use(
  (config: InternalAxiosRequestConfig) => {
    const token = localStorage.getItem('portal-admin-token')
    if (token && config.headers) {
      config.headers.Authorization = `Bearer ${token}`
    }
    // 确保 Content-Type 始终是 application/json
    if (config.headers) {
      config.headers['Content-Type'] = 'application/json'
    }
    return config
  },
  (error) => {
    return Promise.reject(error)
  }
)

// 处理需要跳转登录的错误码
const handleAuthError = (code: number) => {
  // 401 未授权、1004 Token过期、1005 Token无效都需要跳转登录
  if (
    code === ResponseCode.UNAUTHORIZED ||
    code === ResponseCode.TOKEN_EXPIRED ||
    code === ResponseCode.TOKEN_INVALID
  ) {
    localStorage.removeItem('portal-admin-token')
    router.push('/login')
  }
}

// 获取错误消息
const getErrorMessage = (code: number, defaultMessage?: string): string => {
  // 优先使用响应码对应的消息
  if (ResponseCodeMsg[code as ResponseCode]) {
    return ResponseCodeMsg[code as ResponseCode]
  }
  // 其次使用服务器返回的消息
  if (defaultMessage) {
    return defaultMessage
  }
  // 最后使用默认消息
  return '请求失败'
}

// 响应拦截器
service.interceptors.response.use(
  (response: AxiosResponse<ApiResponse>) => {
    const res = response.data
    
    // 如果返回的状态码不是成功，说明有错误
    if (res.code !== ResponseCode.SUCCESS) {
      const errorMessage = getErrorMessage(res.code, res.message)
      ElMessage.error(errorMessage)
      
      // 处理需要跳转登录的错误
      handleAuthError(res.code)
      
      return Promise.reject(new Error(errorMessage))
    }
    
    // 返回修改后的响应，将 ApiResponse 作为 data
    response.data = res
    return response
  },
  (error) => {
    let message = '网络连接失败'
    
    if (error.response) {
      const status = error.response.status
      const responseData = error.response.data
      
      // 如果响应体中有业务错误码，优先使用业务错误码
      if (responseData?.code) {
        message = getErrorMessage(responseData.code, responseData.message)
        handleAuthError(responseData.code)
      } else {
        // 否则使用 HTTP 状态码对应的消息
        switch (status) {
          case ResponseCode.BAD_REQUEST:
            message = ResponseCodeMsg[ResponseCode.BAD_REQUEST]
            break
          case ResponseCode.UNAUTHORIZED:
            message = ResponseCodeMsg[ResponseCode.UNAUTHORIZED]
            handleAuthError(ResponseCode.UNAUTHORIZED)
            break
          case ResponseCode.FORBIDDEN:
            message = ResponseCodeMsg[ResponseCode.FORBIDDEN]
            break
          case ResponseCode.NOT_FOUND:
            message = ResponseCodeMsg[ResponseCode.NOT_FOUND]
            break
          case ResponseCode.METHOD_NOT_ALLOWED:
            message = ResponseCodeMsg[ResponseCode.METHOD_NOT_ALLOWED]
            break
          case ResponseCode.CONFLICT:
            message = ResponseCodeMsg[ResponseCode.CONFLICT]
            break
          case ResponseCode.TOO_MANY_REQUESTS:
            message = ResponseCodeMsg[ResponseCode.TOO_MANY_REQUESTS]
            break
          case ResponseCode.INTERNAL_SERVER_ERROR:
            message = ResponseCodeMsg[ResponseCode.INTERNAL_SERVER_ERROR]
            break
          case ResponseCode.BAD_GATEWAY:
            message = ResponseCodeMsg[ResponseCode.BAD_GATEWAY]
            break
          case ResponseCode.SERVICE_UNAVAILABLE:
            message = ResponseCodeMsg[ResponseCode.SERVICE_UNAVAILABLE]
            break
          default:
            message = responseData?.message || `连接错误${status}`
        }
      }
    }
    
    ElMessage.error(message)
    return Promise.reject(error)
  }
)

// 请求去重：防止相同请求重复发送
const pendingRequests = new Map<string, Promise<any>>()

// 生成请求唯一标识（对对象进行排序，确保相同内容生成相同 key）
const generateRequestKey = (url: string, data?: any): string => {
  if (!data) {
    return `${url}_`
  }
  
  // 对对象进行排序后序列化，确保相同内容生成相同 key
  const sortedData = (() => {
    if (typeof data !== 'object' || data === null) {
      return data
    }
    
    if (Array.isArray(data)) {
      return data.map(item => 
        typeof item === 'object' && item !== null 
          ? Object.keys(item).sort().reduce((acc, key) => {
              acc[key] = item[key]
              return acc
            }, {} as any)
          : item
      )
    }
    
    // 对象：按键名排序
    return Object.keys(data).sort().reduce((acc, key) => {
      const value = data[key]
      if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
        acc[key] = Object.keys(value).sort().reduce((obj, k) => {
          obj[k] = value[k]
          return obj
        }, {} as any)
      } else {
        acc[key] = value
      }
      return acc
    }, {} as any)
  })()
  
  try {
    const dataStr = JSON.stringify(sortedData)
    return `${url}_${dataStr}`
  } catch {
    // 如果序列化失败，使用原始数据
    return `${url}_${String(data)}`
  }
}

// 清理已完成的请求（延迟清理，避免立即重复请求）
const clearPendingRequest = (key: string) => {
  setTimeout(() => {
    pendingRequests.delete(key)
  }, 100) // 100ms 后清理，防止快速重复点击
}

// 封装请求方法 - 所有请求都使用 POST，Content-Type 为 application/json
const request = {
  // GET 请求改为 POST，参数作为 body 发送
  get<T = any>(url: string, params?: any): Promise<ApiResponse<T>> {
    const key = generateRequestKey(url, params)
    
    // 如果已有相同请求正在进行，返回该请求的 Promise
    if (pendingRequests.has(key)) {
      return pendingRequests.get(key)!
    }
    
    // 创建新请求
    const promise = service.post<ApiResponse<T>>(url, params || {}).then(res => {
      clearPendingRequest(key)
      return res.data
    }).catch(error => {
      clearPendingRequest(key)
      throw error
    })
    
    pendingRequests.set(key, promise)
    return promise
  },
  // POST 请求
  post<T = any>(url: string, data?: any): Promise<ApiResponse<T>> {
    const key = generateRequestKey(url, data)
    
    // 如果已有相同请求正在进行，返回该请求的 Promise
    if (pendingRequests.has(key)) {
      return pendingRequests.get(key)!
    }
    
    // 创建新请求
    const promise = service.post<ApiResponse<T>>(url, data || {}).then(res => {
      clearPendingRequest(key)
      return res.data
    }).catch(error => {
      clearPendingRequest(key)
      throw error
    })
    
    pendingRequests.set(key, promise)
    return promise
  },
  // PUT 请求改为 POST，参数作为 body 发送
  put<T = any>(url: string, data?: any): Promise<ApiResponse<T>> {
    const key = generateRequestKey(url, data)
    
    // 如果已有相同请求正在进行，返回该请求的 Promise
    if (pendingRequests.has(key)) {
      return pendingRequests.get(key)!
    }
    
    // 创建新请求
    const promise = service.post<ApiResponse<T>>(url, data || {}).then(res => {
      clearPendingRequest(key)
      return res.data
    }).catch(error => {
      clearPendingRequest(key)
      throw error
    })
    
    pendingRequests.set(key, promise)
    return promise
  },
  // DELETE 请求改为 POST，参数作为 body 发送
  delete<T = any>(url: string, params?: any): Promise<ApiResponse<T>> {
    const key = generateRequestKey(url, params)
    
    // 如果已有相同请求正在进行，返回该请求的 Promise
    if (pendingRequests.has(key)) {
      return pendingRequests.get(key)!
    }
    
    // 创建新请求
    const promise = service.post<ApiResponse<T>>(url, params || {}).then(res => {
      clearPendingRequest(key)
      return res.data
    }).catch(error => {
      clearPendingRequest(key)
      throw error
    })
    
    pendingRequests.set(key, promise)
    return promise
  }
}

export default request

